////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file   CollabRCBot\VariableTreeNode.h
///
/// @brief  Declares the VariableTreeNode class
////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include "ComputationalTreeNode.h"
#include "ComputationalTreeNodeVisitor.h"

namespace CollabRC 
{
    namespace Bot
    {
        namespace AI
        {
            /**
             * @brief Implementation of a ComputationalTreeNode which
             * represents a variable in a computation.
             *
             * The variable is remembered by reference. The reference must
             * remain valid while this object is in use, or attempts to call
             * Compute() may fail due to an illegal memory access.
             * @version $Id$
             * @author Matthew P. Del Buono
             * @tparam the type which is represented by this class. The type
             * must be able to be cast to a float via a C-style cast.
             */
            template <class T>
            class VariableTreeNode : public ComputationalTreeNode
            {
            private:
                /// The variable that is being tracked
                const volatile T& m_variable;

                /** Disallow use of the assignment operator */
                const VariableTreeNode& operator=(const VariableTreeNode&);
            public:
                /**
                 * @brief Creates a new VariableTreeNode which represents
                 * the specified variable.
                 * @warning The variable's address is retained to allow it
                 * to be updated without use of this object. The address must
                 * remain valid while this object is in use or an invalid
                 * memory access may result.
                 * @param var the variable to track
                 */
                inline VariableTreeNode(const volatile T& var) : m_variable(var) { };

                /**
                 * @brief Creates a copy of this VariableTreeNode, tracking
                 * the same variable.
                 * @warning The variable's address is subject to the same
                 * constraints as in VariableTreeNode(const volatile T&).
                 * @param copy the VariableTreeNode to copy
                 */
                inline VariableTreeNode(const VariableTreeNode& copy):m_variable(copy.m_variable) { };

                /**
                 * @brief Deallocates this object and all associated resources
                 */
                inline virtual ~VariableTreeNode(void) { };

                /** {@inheritDoc} */
                virtual ComputationalTreeNode* Clone() const
                {
                    return new VariableTreeNode(*this);
                }

                /** {@inheritDoc} */
                virtual float Compute() const
                {
                    return (float) m_variable;
                }

                /** {@inheritDoc} */
                virtual unsigned int GetBranchDepth() const
                {
                    // This is always the end
                    return 1;
                }

                /** {@inheritDoc} */
                virtual const ComputationalTreeNode& GetRandomBranch(unsigned int depth) const
                {
                    depth = depth; // avoid warnings

                    // There's nowhere else to go, so we must take this branch no matter
                    // what the depth is
                    return *this;
                }

                /** {@inheritDoc} */
                virtual ComputationalTreeNode* Mutate(unsigned int depth) const
                {
                    depth = depth; // Avoid warnings

                    // Mutating a VariableTreeNode is a no-op, so just clone it
                    return Clone();
                }

                /** {@inheritDoc} */
                virtual void Accept(ComputationalTreeNodeVisitor& visitor)
                {
                    visitor.Visit(*this);
                }
            };
        }
    }
}
